<?php

namespace addons\qrcode\controller;

use think\addons\Controller;
use think\exception\HttpResponseException;
use think\Response;

/**
 * 二维码生成
 *
 */
class Index extends Controller
{
    public function index()
    {
        $config = get_addon_config('qrcode');
        $this->assign('config', $config);
        return $this->view->fetch();
    }

    /**
     * 生成二维码图片
     *
     * @return Response
     */
    public function build()
    {
        $config = get_addon_config('qrcode');

        // 限制来源
        if (isset($config['limitreferer']) && $config['limitreferer']) {
            $referer = $this->request->server('HTTP_REFERER', '');
            $refererInfo = parse_url($referer);
            $refererHost = $referer && $refererInfo ? $refererInfo['host'] : '';
            $refererHostArr = explode('.', $refererHost);
            $wildcardDomain = '';
            if (count($refererHostArr) > 2) {
                $refererHostArr[0] = '*';
                $wildcardDomain = implode('.', $refererHostArr);
            }
            $allowRefererList = $config['allowrefererlist'] ?? '';
            $domainArr = explode("\n", str_replace("\r", "", $allowRefererList));
            $domainArr = array_filter(array_unique($domainArr));
            $domainArr[] = request()->host(true);

            $inAllowList = false;

            if (in_array('*', $domainArr) || ($refererHost && in_array($refererHost, $domainArr)) || ($wildcardDomain && in_array($wildcardDomain, $domainArr))) {
                $inAllowList = true;
            }

            if (!$inAllowList && (!$referer && $config['allowemptyreferer'])) {
                $inAllowList = true;
            }

            if (!$inAllowList) {
                return $this->generateErrorImage('暂无权限:来源不匹配');
            }
        }

        $params = $this->request->get();
        $params = array_intersect_key($params, array_flip(['text', 'size', 'padding', 'errorlevel', 'foreground', 'background', 'logo', 'logosize', 'logopath', 'label', 'labelmargin', 'labelfontsize', 'labelalignment', 'labelfontcolor']));

        $text = $this->request->get('text', $config['text'], 'trim');
        $label = $this->request->get('label', $config['label'], 'trim');

        $limitTextRegex = $config['limittextregex'] ?? '';
        $limitLabelRegex = $config['limitlabelregex'] ?? '';

        // 验证字符串是否符合正则
        try {
            if ($limitTextRegex) {
                $this->validateWithRegex($text, $limitTextRegex);
            }
            if ($limitLabelRegex) {
                $this->validateWithRegex($label, $limitLabelRegex);
            }
        } catch (HttpResponseException $e) {
            $response = $e->getResponse();
            return $this->generateErrorImage($response->getContent());
        } catch (\Exception $e) {
            // 生成错误提示图片并输出
            return $this->generateErrorImage($e->getMessage());
        }

        $params['text'] = $text;
        $params['label'] = $label;

        try {
            $qrCode = \addons\qrcode\library\Service::qrcode($params);
        } catch (\Exception $e) {
            return $this->generateErrorImage($e->getMessage());
        }

        $mimetype = $config['format'] == 'png' ? 'image/png' : 'image/svg+xml';

        $response = Response::create()->header("Content-Type", $mimetype);

        header('Content-Type: ' . $qrCode->getMimeType());
        $response->content($qrCode->getString());

        // 写入文件
        if ($config['writefile']) {
            $qrcodePath = ROOT_PATH . 'public/uploads/qrcode/';
            if (!is_dir($qrcodePath)) {
                @mkdir($qrcodePath);
            }
            if (is_really_writable($qrcodePath)) {
                $filePath = $qrcodePath . md5(implode('', $params)) . '.' . $config['format'];
                $qrCode->saveToFile($filePath);
            }
        }

        return $response;
    }

    /**
     * 验证字符串是否符合至少一个正则表达式
     *
     * @param string $input       要验证的字符串
     * @param string $regexConfig 多行正则表达式字符串
     * @throws HttpResponseException
     */
    protected function validateWithRegex(string $input, string $regexConfig): void
    {
        $regexList = explode("\n", str_replace("\r", "", $regexConfig));
        $regexList = array_unique(array_filter($regexList)); // 去除空行并去重

        if (empty($regexList)) {
            return; // 没有配置正则时跳过验证
        }

        foreach ($regexList as $pattern) {
            set_error_handler(function (int $errno, string $errstr) use ($pattern) {
                throw new \RuntimeException("系统错误:正则表达式错误");
            });

            try {
                $result = @preg_match($pattern, $input);
                restore_error_handler();

                if ($result === false) {
                    // 正则语法错误
                    $response = Response::create('系统错误:服务器内部错误', 'html', 500);
                    throw new HttpResponseException($response);
                }

                if ($result === 1) {
                    // 匹配成功，直接返回，不再继续判断
                    return;
                }
            } catch (\Throwable $e) {
                restore_error_handler();
                throw $e;
            }
        }

        // 所有正则都不匹配，抛出错误
        $response = Response::create('参数错误:正则不匹配', 'html', 400);
        throw new HttpResponseException($response);
    }

    /**
     * 生成一个包含错误信息的图片
     *
     * @param string $message 错误信息
     * @return Response
     */
    protected function generateErrorImage(string $message): Response
    {
        $config = get_addon_config('qrcode');

        // 设置字体路径（确保该字体存在且可读）
        $fontPath = ROOT_PATH . 'public' . $config['labelfontpath'];

        $width = 300;
        $height = 300;

        // 创建画布
        $im = imagecreatetruecolor($width, $height);
        $bgColor = imagecolorallocate($im, 255, 255, 255); // 白色背景
        $textColor = imagecolorallocate($im, 255, 0, 0);   // 红色文字

        imagefilledrectangle($im, 0, 0, $width, $height, $bgColor);

        // 使用 imagettftext 支持中文
        $fontSize = 14;
        $angle = 0;

        // 计算文本居中位置
        $textBox = imagettfbbox($fontSize, $angle, $fontPath, $message);
        if ($textBox === false) {
            $x = 10;
            $y = 50;
        } else {
            $textWidth = $textBox[2] - $textBox[0];
            $textHeight = $textBox[1] - $textBox[5];
            $x = ($width - $textWidth) / 2;
            $y = ($height + $textHeight) / 2;
        }

        // 绘制文本
        imagettftext($im, $fontSize, $angle, $x, $y, $textColor, $fontPath, $message);

        // 输出图片
        ob_start();
        imagepng($im);
        imagedestroy($im);
        $imageData = ob_get_clean();

        return Response::create($imageData, 'image/png')->header('Content-Type', 'image/png');
    }
}
